﻿using NL.AdreesableAsset;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Profiling;
using UnityEngine.Rendering;

namespace NL.Advanced
{
    [DefaultExecutionOrder(-500)]
    public class SETTING : MonoBehaviour
    {
        public class Devive
        {
            //设备标识符.
            public string DUID, DeviceModel, OperatingSystem;
            public DeviceType DeviceType;
            //处理器信息
            public string ProcessorType;
            public int ProcessorCount, ProcessorFrequency;

            public string GraphicsDeviceName;
            public GraphicsDeviceType GraphicsDeviceType;
            //内存信息
            public int MemorySize, GraphicsMemorySize;

            const int DefaultGraphicsLevel = 1;
            string Summery;
            public Devive()
            {
                _GetDeiveInfo();
            }

            void _GetDeiveInfo()
            {
                try
                {
                    DUID = SystemInfo.deviceUniqueIdentifier;

                    DeviceModel = SystemInfo.deviceModel;

                    DeviceType = SystemInfo.deviceType;

                    OperatingSystem = SystemInfo.operatingSystem;




                    ProcessorCount = SystemInfo.processorCount;
                    ProcessorFrequency = SystemInfo.processorFrequency;
                    ProcessorType = SystemInfo.processorType;

                    MemorySize = SystemInfo.systemMemorySize;
                    GraphicsMemorySize = SystemInfo.graphicsMemorySize;


                    GraphicsDeviceName = SystemInfo.graphicsDeviceName;
                    GraphicsDeviceType = SystemInfo.graphicsDeviceType;




                    Summery = this.TOIni().ToString('\n');
                }
                catch (Exception e)
                {
                    LOG.Add($"[Runtime._GetDeiveInfo]:Error:{e.Message}");
                }

            }

            public bool IsHighDevice()
            {
                return MemorySize >= 4 * 1024 || ProcessorCount >= 6;
            }

            public static int PerformanceCheck(string jsontext)
            {
                DevicesGPULevelConfig cfg = JsonUtility.FromJson<DevicesGPULevelConfig>(jsontext);

                if (cfg == null) { return DefaultGraphicsLevel; }//返回缺省等级中配。
                string graphicsDeviceName = SystemInfo.graphicsDeviceName;

                var levels = cfg.levels;

                for (int i = 0; i < levels.Count; i++)
                {
                    var level = levels[i];
                    var models = level.GPUModels;
                    for (int j = 0; j < models.Count; j++)
                    {
                        if (graphicsDeviceName == models[j])
                        {
                            return level.level;
                        }
                    }
                }

                return DefaultGraphicsLevel;
            }

            public override string ToString() => Summery;
        }

        public class Runtime
        {
            public long TotalAllocated, MonoUsed, MonoHeap, TotalReserved, UnusedReserved, GraphicsDriver;
            public float CheckTimeLast;
            public Runtime Now()
            {

                TotalAllocated = Profiler.GetTotalAllocatedMemoryLong();

                MonoUsed = Profiler.GetMonoUsedSizeLong();

                MonoHeap = Profiler.GetMonoHeapSizeLong();

                //GraphicsDriver = Profiler.GetAllocatedMemoryForGraphicsDriver();


                TotalReserved = Profiler.GetTotalReservedMemoryLong();

                UnusedReserved = Profiler.GetTotalUnusedReservedMemoryLong();

                CheckTimeLast = Time.realtimeSinceStartup;

                return this;
            }
            //public int Minutes { get { return (int)Time.time / 60; } }
            //public int Seconds { get { return (int)Time.time % 60; } }
            public override string ToString()
            {
                return CheckTimeLast.ToString("00") + ":\n"
                    + "\tTotalAllocated:\t" + (TotalAllocated / 1024f / 1024.0f).ToString("###,###.##") + "[MB] \n "

                    + "\tTotalReserved: \t" + (TotalReserved / 1024f / 1024.0f).ToString("###,###") + "[MB]\n"
                    + "\tUnuse:         \t" + (UnusedReserved / 1024f / 1024.0f).ToString("###,###") + "[MB]\n"
                    //+ "\tGraphicsDriver:\t" + (GraphicsDriver / 1024f / 1024.0f).ToString("###,###") + "[MB]\n"

                    + "\tMonoUsed:      \t" + (MonoUsed / 1024f / 1024.0f).ToString("###,###") + "[MB]\n"
                    + "\tMonoHeap:      \t" + (MonoHeap / 1024f / 1024.0f).ToString("###,###") + "[MB]\n"
                    ;
            }




        }

        public bool RunInBackGround = true;



        const string KEY_QUALITY = "GOT-SETTING-QUALITY";

        public static int QualityLevel
        {
            get => QualitySettings.GetQualityLevel();
            set => QualitySettings.SetQualityLevel(value, true);
        }
        public static float RenderScale
        {
            get
            {
                return 1;
                //var pipeline = QualitySettings.renderPipeline as UniversalRenderPipelineAsset;

                //if (pipeline == null) return 0;

                //return pipeline.renderScale;
            }
            set
            {
                //if (value <= 0) return;

                //var pipeline = QualitySettings.renderPipeline as UniversalRenderPipelineAsset;

                //if (pipeline == null) return;

                //pipeline.renderScale = value;
            }
        }
        [Header("默认得渲染等级0;1;2 低中高.")]
        public int DefualtQualityLevel = 0;

        [Header("设备能力判断-内存;处理器几核")]
        public int DeviceHighForMemory = 4 * 1024;
        public int DeviceHighForProcessorCount = 6;

        [Header("性能检测")]
        public int DeviceDetectFPSRef = 30;
        //public int PerformanceHigh = 98;
        public int PerformanceLow = 60;

        //public bool EnableLog = true;
        //public static bool LOGAble => INSTANCE != null ? INSTANCE.EnableLog : true;

        public static SETTING INSTANCE;
        Devive _Devive;
        protected PERFORMANCE _Performance;

        public bool Ready = false;
        // Start is called before the first frame update
        void Awake()
        {
            INSTANCE = this;
            Application.runInBackground = RunInBackGround;



            _Performance = GetComponentInChildren<PERFORMANCE>();

            _Devive = new Devive();
            Ready = false;
        }

        string LogText;
        //public string DeviceRefile = "info/device_graphicslevel.info";

        public UnityEvent<string> SavingQualitySet;
        IEnumerator Start()
        {
            LOG.Show(gameObject, () =>
            {
                LogText = $"FPS={((int)SYS.FPS).ToString("000")}  Quality={QualityLevel}@{RenderScale}  TimeScale ={Time.timeScale}\n";


                if (_Runtime != null && Time.realtimeSinceStartup - _Runtime.CheckTimeLast < 10)
                    LogText += $"\nRunTime:{_Runtime.ToString()}\n";
                if (_Devive != null && Time.time - _DeviceTime < 10)
                    LogText += $"\nDevoce:{_Devive.ToString()}\n";

                return LogText;
            });

            //HTTP.Request<string>(DeviceRefile, true).Wait((w, s) =>
            //{
            //    Devive.PerformanceCheck(s);
            //});



            //检查是否需要检测 设备.....
            int quality = PlayerPrefs.GetInt(KEY_QUALITY, DefualtQualityLevel);


            if (quality < 0)
            {
                LOG.Add($"[SETTING.Start]:..................");

                // 按照设备信息 判断.
                if (_Devive.MemorySize >= DeviceHighForMemory || _Devive.ProcessorCount >= DeviceHighForProcessorCount)
                {
                    LOG.Add($"[SETTING.Start]:quality = 2; {_Devive.MemorySize},{_Devive.ProcessorCount}");
                    quality = 2;
                }
                else
                {
                    // 按照性能检测 判断
                    yield return new WaitForSeconds(2);
                    _Performance?.Detect(10, DeviceDetectFPSRef, w =>
                    {
                        if (w >= 100)
                            quality = 2;
                        else if (w > PerformanceLow)
                            quality = 1;
                        else
                            quality = 0;

                        LOG.Add($"[SETTING.Start]:quality = {quality}; Performance={w}");
                    });
                    while (_Performance != null && _Performance.FPSPrechecking)
                        yield return new WaitForSeconds(0.1f);


                }
            }



            QUALITY_USE(quality, true, true);

            Ready = true;
        }




        public static void SPEED_UP(float dp)
        {
            Time.timeScale += dp;
            if (Time.timeScale < 0.1f)
                Time.timeScale = -.1f;
        }

        public static void QUALITY_USE(int index, bool deeply, bool isAuto = false)
        {

            int Lastquality = PlayerPrefs.GetInt(KEY_QUALITY, -1);
            QualitySettings.SetQualityLevel(index, deeply);
            PlayerPrefs.SetInt(KEY_QUALITY, index);
            PlayerPrefs.Save();
            string str = string.Concat(Lastquality, ";", index, ";", isAuto ? 1 : 0);
            INSTANCE.SavingQualitySet?.Invoke(str);
            LOG.Add($"[SETTING.QUALITY_USE]:{index}");
        }

        public static void QUALITY_USE(int index, bool isAuto = false)
        {
            QUALITY_USE(index, false, isAuto);
        }
        Runtime _Runtime;

        float _RuntimeCheck;
        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.P))
            {
                GetRunTime();
            }
        }

        public void SetQuality(string w)
        {

            int m = int.MinValue;
            if (!int.TryParse(w, out m)) return;

            if (m >= 0 && m <= 2)
                QualityLevel = m;


        }
        public void SetRenderScale(string w)
        {
            float m = 0;
            if (!float.TryParse(w, out m)) return;

            if (m <= 0) return;

            RenderScale = m;

        }

        public void SetTimeScale(string w)
        {
            float m = 0;
            if (!float.TryParse(w, out m)) return;

            if (m < 0) return;

            Time.timeScale = m;
        }

        public void GetRunTime()
        {

            _Runtime = _Runtime ?? new Runtime();
            _Runtime?.Now();
            LOG.Add($"[SETTING]Runtime:{_Runtime.ToString()}");
        }

        float _DeviceTime;
        public void GetDevice()
        {
            _Devive = _Devive ?? new Devive();
            LOG.Add($"[SETTING]Devive:{_Devive.ToString()}");

            _DeviceTime = Time.time;
        }

        public static void FPSLock(bool locked)
        {
            Application.targetFrameRate = locked ? 36 : 1000;
        }
        public void LockFPS(int max)
        {
            Application.targetFrameRate = max;
        }

        public void HealthDetect(string w)
        {
            var pams = w.Split(NLConst.CHAR_INNER);

            int count, fps = 0;
            if (!int.TryParse(pams[0], out count)) return;
            if (!int.TryParse(pams[1], out fps)) return;


            _Performance.Detect(count, fps, null);
        }

        public void AAClean()
        {
            AA.CLEANLoad();
        }

        public void ClearSaving(string w)
        {
            PlayerPrefs.DeleteAll();
        }

    }

    [Serializable]
    public class DevicesGPULevelConfig
    {
        public List<GPULevel> levels;
    }

    [Serializable]
    public class GPULevel
    {
        public int level;
        public List<string> GPUModels;
    }
}

